package triaina.webview.worker;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;
import com.squareup.okhttp.ResponseBody;
import java.io.File;
import java.io.IOException;
import java.util.Set;
import triaina.commons.http.CommonHttpClient;
import triaina.commons.utils.BundleUtils;
import triaina.commons.utils.CloseableUtils;
import triaina.commons.workerservice.AbstractNetworkWorker;
import triaina.commons.workerservice.WorkerService;
import triaina.webview.entity.Result;
import triaina.webview.entity.device.NetHttpSendParams;
import triaina.webview.entity.device.NetHttpSendResult;
import triaina.webview.entity.device.SendNotificationParams;
import triaina.webview.job.HttpRequestJob;
import triaina.webview.receiver.CallbackReceiver;
public class HttpRequestWorker extends AbstractNetworkWorker<HttpRequestJob> {
private static final String TAG = HttpRequestWorker.class.getSimpleName();
private static final int MAX_RETRY = 3;
private static final String POST_METHOD = "POST";
private static final String GET_METHOD = "GET";
private static final String PUT_METHOD = "PUT";
private static final String DELETE_METHOD = "DELETE";
private static final String MULTIPART = "multipart/form-data";
private static final String CONTENT_TYPE = "content-type";
public static final String FILE_TYPE = "File";
private Context mContext;
private NetHttpSendParams mParams;
@Override
public boolean process(HttpRequestJob job, int retry, int delayAmount, ResultReceiver receiver, Context context,
Handler handler) throws Exception {
mContext = context;
mParams = job.getParams();
waitForNetworkAvailable();
// 300 seconds
if (delayAmount > 300 || retry > MAX_RETRY) {
fail(job, receiver, CallbackReceiver.TIMEOUT_ERROR_CODE, null);
return false;
}
String method = mParams.getMethod();
Request request = null;
// XXX post only
// TODO other methods
if (POST_METHOD.equals(method)) {
request = createPostRequest(mParams, job.getCookie());
} else {
Log.d(TAG, "sorry " + method + " method is not implemented yet");
}
showProgressNotification(job.getNotificationId(), mParams.getNotification());
OkHttpClient client = null;
Response response = null;
try {
client = CommonHttpClient.getInstance();
response = client.newCall(request).execute();
NetHttpSendResult result = new NetHttpSendResult();
buildResult(result, response);
if (receiver != null) succeed(job, receiver, result, mParams);
} catch (IOException exp) {
return false;
} finally {
if (response != null) CloseableUtils.close(response.body());
CommonHttpClient.closeInstance(client);
}
return true;
}
private void showProgressNotification(Integer id, SendNotificationParams params) {
if (id == null || params == null) return;
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(
WorkerService.ACTION_CANCEL_TASK), 0);
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(mContext)
.setContentTitle(params.getProgress())
.setContentText(params.getSummary())
.setSmallIcon(android.R.drawable.stat_sys_upload).setTicker(params.getProgress())
.setContentIntent(pendingIntent)
.setOngoing(true).setWhen(System.currentTimeMillis()).getNotification();
notificationManager.notify(id, notification);
}
private void showCompletedNotification(Integer id, SendNotificationParams params) {
if (id == null || params == null) return;
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(mContext).setContentTitle(params.getCompleted())
.setSmallIcon(android.R.drawable.stat_sys_upload_done).setContentIntent(pendingIntent)
.getNotification();
notificationManager.notify(id, notification);
}
private void showFailedNotification(Integer id, SendNotificationParams params) {
if (id == null || params == null)
return;
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, new Intent(),
Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager notificationManager = (NotificationManager) mContext
.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(mContext).setContentTitle(params.getFailed())
.setSmallIcon(android.R.drawable.stat_sys_warning).setContentIntent(pendingIntent).getNotification();
notificationManager.notify(id, notification);
}
public void succeed(HttpRequestJob job, ResultReceiver receiver, Result result, NetHttpSendParams params) {
showCompletedNotification(job.getNotificationId(), params.getNotification());
Bundle bundle = new Bundle();
bundle.putParcelable(CallbackReceiver.RESULT, result);
receiver.send(CallbackReceiver.SUCCESS_CODE, bundle);
}
public void fail(HttpRequestJob job, ResultReceiver receiver, int code, String msg) {
showFailedNotification(job.getNotificationId(), mParams.getNotification());
receiver.send(code, null);
}
private void buildResult(NetHttpSendResult result, Response response) throws IllegalStateException, IOException {
result.setCode(response.code() + "");
Headers headers = response.headers();
Bundle bundle = new Bundle();
for (int i = 0; i < headers.size(); i++) {
bundle.putString(headers.name(i), headers.value(i));
}
result.setHeaders(bundle);
ResponseBody responseBody = response.body();
String res = responseBody != null ? responseBody.string() : null;
result.setResponseText(res);
}
private Request createPostRequest(NetHttpSendParams params, String cookie) {
Bundle headers = params.getHeaders();
RequestBody requestBody;
if (headers != null && MULTIPART.equals(BundleUtils.getStringByCaseInsensitive(headers, CONTENT_TYPE))) {
requestBody = createMultipartRequestBody(params);
} else {
String contentType = null;
if (headers != null) {
contentType = BundleUtils.getStringByCaseInsensitive(headers, CONTENT_TYPE);
}
requestBody = createRequestBody(params, contentType);
}
Request.Builder builder = new Request.Builder()
.url(params.getUrl())
.post(requestBody);
if (headers != null && !MULTIPART.equals(BundleUtils.getStringByCaseInsensitive(headers, CONTENT_TYPE))) {
Set<String> keys = headers.keySet();
for (String key : keys) {
builder.addHeader(key, headers.getString(key));
}
}
if (cookie != null) {
builder.addHeader("Cookie", cookie);
}
return builder.build();
}
private RequestBody createMultipartRequestBody(NetHttpSendParams params) {
Bundle body = params.getBody();
if (body == null) return null;
MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
Set<String> keys = body.keySet();
for (String key : keys) {
String rawBody = body.getString(key);
if (rawBody != null) {
builder.addFormDataPart(key, rawBody);
continue;
}
Bundle part = body.getBundle(key);
if (part != null) {
if (FILE_TYPE.equals(part.getString("type"))) {
File file = new File(part.getString("value"));
RequestBody requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
builder.addFormDataPart(key, file.getName(), requestBody);
}
continue;
}
}
return builder.build();
}
private RequestBody createRequestBody(NetHttpSendParams params, String contentType) {
MediaType mediaType = MediaType.parse(contentType == null ? "text/plain" : contentType);
return params.getRawBody() == null ? null : RequestBody.create(mediaType, params.getRawBody());
}
}